package com.eastfair.imaster.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.nacos.common.utils.Objects;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.eastfair.boot.request.PageParams;
import com.eastfair.boot.service.SuperCacheServiceImpl;
import com.eastfair.cache.operations.ConferenceTopicCacheKeyBuilder;
import com.eastfair.config.api.ConfigServiceFeign;
import com.eastfair.config.dto.AttachmentDTO;
import com.eastfair.config.vo.AttachmentVO;
import com.eastfair.constant.BusinessConstant;
import com.eastfair.core.base.R;
import com.eastfair.core.base.entity.SuperEntity;
import com.eastfair.core.context.ContextUtil;
import com.eastfair.core.exception.code.ExceptionCode;
import com.eastfair.core.model.CacheKeyBuilder;
import com.eastfair.core.utils.ConvertUtil;
import com.eastfair.core.utils.StringUtils;
import com.eastfair.enums.BusinessTypeEnum;
import com.eastfair.imaster.dao.ConferenceTopicMapper;
import com.eastfair.imaster.dto.ConferenceTopicDTO;
import com.eastfair.imaster.dto.ConferenceTopicPageQuery;
import com.eastfair.imaster.entity.ConferenceTopic;
import com.eastfair.imaster.enumeration.ConferenceTopicSpeakerTypeEnum;
import com.eastfair.imaster.service.ConferenceTopicService;
import com.eastfair.imaster.service.ConferenceTopicSpeakerService;
import com.eastfair.imaster.service.SelfAttachmentService;
import com.eastfair.imaster.vo.ConferenceTopicVO;
import com.eastfair.projectcore.api.ProjectCoreServiceFeign;
import com.eastfair.core.snowflake.DefaultUidGenerator;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 业务实现类
 * 论坛主题
 * </p>
 *
 * @author zjn
 * @date 2021-08-31
 */
@Slf4j
@Service
@DS("#thread.tenant")
public class ConferenceTopicServiceImpl extends SuperCacheServiceImpl<ConferenceTopicMapper, ConferenceTopic> implements ConferenceTopicService {

    @Autowired
    ProjectCoreServiceFeign projectCoreServiceFeign;
    @Autowired
    private ConferenceTopicSpeakerService conferenceTopicSpeakerService;
    @Autowired
    private SelfAttachmentService selfAttachmentService;
    @Autowired
    private ConfigServiceFeign configServiceFeign;

    @Override
    protected CacheKeyBuilder cacheKeyBuilder() {
        return new ConferenceTopicCacheKeyBuilder();
    }

    /**************sharding 分库分表操作 *****************/
    @Override
    public boolean updateByIdOfShard(ConferenceTopic entity) {
        UpdateWrapper<ConferenceTopic> updateWrapper = new UpdateWrapper<>();
        //可将指定字段更新为null
        updateWrapper.lambda().eq(ConferenceTopic::getProjectId, ContextUtil.getProjectId()).eq(ConferenceTopic::getId, entity.getId());
        entity.setProjectId(null);
        //删除缓存
        delCache(entity);
        return SqlHelper.retBool(this.getBaseMapper().update(entity, updateWrapper));
    }

    /**
     * 处理新增相关处理
     *
     * @param model 实体
     * @return 是否成功
     */
    @Override
    protected R<Boolean> handlerSave(ConferenceTopic model) {
        //雪花ID
        model.setId(DefaultUidGenerator.getUidOfProjectId(ContextUtil.getProjectId()));
        model.setProjectId(ContextUtil.getProjectId());
        return R.successDef();
    }

    @Override
    @GlobalTransactional(name = "saveConferenceTopic", rollbackFor = Exception.class)
    public R<Boolean> saveConferenceTopic(ConferenceTopicDTO conferenceTopicDTO) {
        if (StringUtils.isBlank(conferenceTopicDTO.getName(), conferenceTopicDTO.getAddress())) {
            return R.fail(ExceptionCode.ERROR_NULL_PARAMS);
        }
        conferenceTopicDTO.setProjectId(ContextUtil.getProjectId());
        ConferenceTopic conferenceTopic = BeanUtil.copyProperties(conferenceTopicDTO, ConferenceTopic.class);
        save(conferenceTopic);

        // 保存主持人
        if (conferenceTopicDTO.getHostConferenceTopicSpeakerDTOList() != null && !conferenceTopicDTO.getHostConferenceTopicSpeakerDTOList().isEmpty()) {
            conferenceTopicSpeakerService.saveConferenceTopicSpeakers(conferenceTopicDTO.getHostConferenceTopicSpeakerDTOList(), conferenceTopic.getId(), ConferenceTopicSpeakerTypeEnum.HOST);
        }

        // 保存演讲者
        if (conferenceTopicDTO.getConferenceTopicSpeakerDTOList() != null && !conferenceTopicDTO.getConferenceTopicSpeakerDTOList().isEmpty()) {
            conferenceTopicSpeakerService.saveConferenceTopicSpeakers(conferenceTopicDTO.getConferenceTopicSpeakerDTOList(), conferenceTopic.getId(), ConferenceTopicSpeakerTypeEnum.SPEAKER);
        }

        // 保存附件
        if (conferenceTopicDTO.getAttachmentDTOList() != null && !conferenceTopicDTO.getAttachmentDTOList().isEmpty()) {
            selfAttachmentService.saveAttachments(conferenceTopicDTO.getAttachmentDTOList(), BusinessTypeEnum.CONFERENCE_TOPIC, conferenceTopic.getId());
        }

        return R.success(Boolean.TRUE);
    }

    @Override
    @GlobalTransactional(name = "deleteById", rollbackFor = Exception.class)
    public R<Boolean> deleteById(Long id) {
        if (id == null) {
            return R.fail(ExceptionCode.ERROR_NULL_PARAMS);
        }

        // 删除主持人和演讲者
        conferenceTopicSpeakerService.deleteByConferenceTopicId(id, null);

        // 删除附件
        configServiceFeign.deleteByBusiness(AttachmentDTO.builder().businessType(BusinessTypeEnum.CONFERENCE_TOPIC.name()).businessId(id).build());

        return R.success(updateByIdOfShard(ConferenceTopic.builder().id(id).isDeleted(BusinessConstant.DELETE_YES).build()));
    }

    @Override
    @GlobalTransactional(name = "updateById", rollbackFor = Exception.class)
    public R<Boolean> updateById(ConferenceTopicDTO conferenceTopicDTO) {
        if (Objects.isNull(conferenceTopicDTO.getId())) {
            return R.fail(ExceptionCode.ERROR_NULL_PARAMS);
        }

        // 修改主持人
        if (conferenceTopicDTO.getHostConferenceTopicSpeakerDTOList() == null || conferenceTopicDTO.getHostConferenceTopicSpeakerDTOList().isEmpty()) {
            conferenceTopicSpeakerService.deleteByConferenceTopicId(conferenceTopicDTO.getId(), ConferenceTopicSpeakerTypeEnum.HOST);
        } else {
            conferenceTopicSpeakerService.deleteAndSaveByConferenceTopicId(conferenceTopicDTO.getHostConferenceTopicSpeakerDTOList(), conferenceTopicDTO.getId(), ConferenceTopicSpeakerTypeEnum.HOST);
        }

        // 修改演讲者
        if (conferenceTopicDTO.getConferenceTopicSpeakerDTOList() == null || conferenceTopicDTO.getConferenceTopicSpeakerDTOList().isEmpty()) {
            conferenceTopicSpeakerService.deleteByConferenceTopicId(conferenceTopicDTO.getId(), ConferenceTopicSpeakerTypeEnum.SPEAKER);
        } else {
            conferenceTopicSpeakerService.deleteAndSaveByConferenceTopicId(conferenceTopicDTO.getConferenceTopicSpeakerDTOList(), conferenceTopicDTO.getId(), ConferenceTopicSpeakerTypeEnum.SPEAKER);
        }

        // 修改资料
        if (conferenceTopicDTO.getAttachmentDTOList() == null || conferenceTopicDTO.getAttachmentDTOList().isEmpty()) {
            configServiceFeign.deleteByBusiness(AttachmentDTO.builder().businessType(BusinessTypeEnum.CONFERENCE_TOPIC.name()).businessId(conferenceTopicDTO.getId()).build());
        } else {
            configServiceFeign.deleteAndSaveAttachmentList(selfAttachmentService.convertAttachments(conferenceTopicDTO.getAttachmentDTOList(), BusinessTypeEnum.CONFERENCE_TOPIC, conferenceTopicDTO.getId()));
        }

        return R.success(updateByIdOfShard(BeanUtil.copyProperties(conferenceTopicDTO, ConferenceTopic.class)));
    }

    @Override
    public R<ConferenceTopicVO> queryById(Long id) {
        if (Objects.isNull(id)) {
            return R.fail(ExceptionCode.ERROR_NULL_ID);
        }
        QueryWrapper<ConferenceTopic> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(ConferenceTopic::getProjectId, ContextUtil.getProjectId()).eq(SuperEntity::getId, id)
                .eq(ConferenceTopic::getIsDeleted, BusinessConstant.DELETE_NO);

        ConferenceTopicVO conferenceTopicVO = BeanUtil.copyProperties(getOne(queryWrapper, false), ConferenceTopicVO.class);

        // 获取主持人
        conferenceTopicVO.setHostConferenceTopicSpeakerVOList(conferenceTopicSpeakerService.getByConferenceTopicId(id, ConferenceTopicSpeakerTypeEnum.HOST, conferenceTopicVO.getHostOrderType()).getData());

        // 获取演讲者
        conferenceTopicVO.setConferenceTopicSpeakerVOList(conferenceTopicSpeakerService.getByConferenceTopicId(id, ConferenceTopicSpeakerTypeEnum.SPEAKER, conferenceTopicVO.getHostOrderType()).getData());

        // 获取附件
        List<AttachmentVO> attachmentVOList = configServiceFeign.getAttachmentListByBusiness(AttachmentDTO.builder().businessType(BusinessTypeEnum.CONFERENCE_TOPIC.name())
                .businessId(id).build()).getData();
        conferenceTopicVO.setAttachmentVOList(attachmentVOList);
        return R.success(conferenceTopicVO);
    }

    @Override
    public Page<ConferenceTopicVO> queryPageList(PageParams<ConferenceTopicPageQuery> params) {
        ConferenceTopic conferenceTopic = BeanUtil.copyProperties(params.getModel(), ConferenceTopic.class);
        QueryWrapper<ConferenceTopic> queryWrapper = buildListBaseWrapper(conferenceTopic);
        return ConvertUtil.convertPage(page(params.buildPage(), queryWrapper), ConferenceTopicVO.class);
    }

    @Override
    public R<Boolean> deleteTopicRelation(Long conferenceId) {
        if (conferenceId == null) {
            return R.fail(ExceptionCode.ERROR_NULL_ID);
        }

        // 删除缓存
        QueryWrapper<ConferenceTopic> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(ConferenceTopic::getProjectId, ContextUtil.getProjectId()).eq(ConferenceTopic::getRelationConferenceId, conferenceId)
                .eq(ConferenceTopic::getIsDeleted, BusinessConstant.DELETE_NO);
        List<ConferenceTopic> conferenceTopicList = list(queryWrapper);
        if (conferenceTopicList != null && !conferenceTopicList.isEmpty()) {
            List<Long> ids = conferenceTopicList.stream().map(ConferenceTopic::getId).collect(Collectors.toList());
            delCache(ids);
        }

        // 修改数据
        UpdateWrapper<ConferenceTopic> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().eq(ConferenceTopic::getProjectId, ContextUtil.getProjectId()).eq(ConferenceTopic::getRelationConferenceId, conferenceId)
                .set(ConferenceTopic::getRelationConferenceId, null);
        return R.success(update(updateWrapper));
    }

    @Override
    public R<List<ConferenceTopicVO>> queryList(ConferenceTopicDTO conferenceTopicDTO) {
        ConferenceTopic conferenceTopic = BeanUtil.copyProperties(conferenceTopicDTO, ConferenceTopic.class);
        QueryWrapper<ConferenceTopic> queryWrapper = buildListBaseWrapper(conferenceTopic);
        return R.success(ConvertUtil.convertList(list(queryWrapper), ConferenceTopicVO.class));
    }

    private QueryWrapper<ConferenceTopic> buildListBaseWrapper(ConferenceTopic conferenceTopic) {
        QueryWrapper<ConferenceTopic> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(ConferenceTopic::getProjectId, ContextUtil.getProjectId()).eq(ConferenceTopic::getIsDeleted, BusinessConstant.DELETE_NO);

        if (!Objects.isNull(conferenceTopic.getIsShelves())) {
            queryWrapper.lambda().eq(ConferenceTopic::getIsShelves, conferenceTopic.getIsShelves());
        }

        if (!StringUtils.isBlank(conferenceTopic.getName())) {
            queryWrapper.lambda().and(wrapper ->
                    wrapper.like(ConferenceTopic::getName, conferenceTopic.getName())
                            .or().like(ConferenceTopic::getEnName, conferenceTopic.getName())
            );
        }
        return queryWrapper;
    }

    @Override
    public R<Boolean> updateEnabledByConferenceId(Long conferenceId, Integer isEnabled) {
        if (Objects.isNull(conferenceId) || Objects.isNull(isEnabled)) {
            return R.fail(ExceptionCode.ERROR_NULL_ID);
        }

        UpdateWrapper<ConferenceTopic> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().eq(ConferenceTopic::getProjectId, ContextUtil.getProjectId()).eq(ConferenceTopic::getRelationConferenceId, conferenceId)
                .set(ConferenceTopic::getIsEnabled, isEnabled);
        return R.success(update(updateWrapper));
    }

    @Override
    public R<Boolean> updateEnabledById(ConferenceTopicDTO conferenceTopicDTO) {
        if (Objects.isNull(conferenceTopicDTO.getId()) || Objects.isNull(conferenceTopicDTO.getIsEnabled())) {
            return R.fail(ExceptionCode.ERROR_NULL_PARAMS);
        }
        UpdateWrapper<ConferenceTopic> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().eq(ConferenceTopic::getProjectId, ContextUtil.getProjectId()).eq(SuperEntity::getId, conferenceTopicDTO.getId())
                .set(ConferenceTopic::getIsEnabled, conferenceTopicDTO.getIsEnabled());
        return R.success(update(updateWrapper));
    }
}
